﻿// Copyright 2012 Jack Bulan (agentgeo)
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.IO;
using GemWorkshop.Formats.Nsbtx;

namespace GemWorkshop.Formats.Nsbmd
{
    public class BMD0Writer
    {
        BinaryWriter writer;
        sBMD0 model;

        public BMD0Writer(sBMD0 model, string outFile)
        {
            //File.WriteAllText(outFile, String.Empty); // Clear the file.
            writer = new BinaryWriter(File.OpenWrite(outFile));
            this.model = model;

            // Write general  header
            WriteHeader();
            // Write model section
            model.header.offset[0] = (uint)writer.BaseStream.Position;
            writer.Write(model.model.type); // MDL0
            writer.Write(model.model.size); // The edited size.
            // 3D Info block
            Write3DInfo();
            // Model Data blocks
            WriteModelData();

            writer.Close();
            writer.Dispose();
        }

        private void WriteHeader()
        {
            writer.BaseStream.Position = 0L; // The start of the file.
            // Write the generic header
            writer.Write(model.header.type);
            writer.Write(model.header.constant);
            writer.Write(model.header.fileSize);
            writer.Write(model.header.headerSize);
            writer.Write(model.header.numSect);

            for (int i = 0; i < model.header.numSect; i++)
                writer.Write(model.header.offset[i]);
        }

        private void Write3DInfo()
        {
            // Header
            writer.Write(model.model.mdlInfo.dummy);
            writer.Write(model.model.mdlInfo.num_objs);
            writer.Write(model.model.mdlInfo.section_size);

            // Unknown
            writer.Write(model.model.mdlInfo.unknownBlock.header_size);
            writer.Write(model.model.mdlInfo.unknownBlock.section_size);
            writer.Write(model.model.mdlInfo.unknownBlock.constant);

            for (int i = 0; i < model.model.mdlInfo.num_objs; i++)
            {
                writer.Write(model.model.mdlInfo.unknownBlock.unknown1[i]);
                writer.Write(model.model.mdlInfo.unknownBlock.unknown2[i]);
            }

            // Data
            writer.Write(model.model.mdlInfo.infoBlock.header_size);
            writer.Write(model.model.mdlInfo.infoBlock.data_size);
            for (int i = 0; i < model.model.mdlInfo.num_objs; i++)
            {
                writer.Write((uint)model.model.mdlInfo.infoBlock.infoData[i]);
                // NOTE: In textures, can be TextInfo or PalInfo,
                // but here it is only a uint...
            }

            // Names
            for (int i = 0; i < model.model.mdlInfo.num_objs; i++)
            {
                char[] name = model.model.mdlInfo.names[i].ToArray();
                int extra = 0x10 - name.Length;
                writer.Write(name);
                if (extra > 0)
                    for (int x = 0; x < extra; x++)
                        writer.Write((byte)0);
            }
        }

        private void WriteModelData()
        {
            for (int m = 0; m < model.model.mdlInfo.num_objs; m++)
            {
                uint offset = (uint)writer.BaseStream.Position - model.header.offset[0];

                WriteModelHeader(m);
            }
        }

        private void WriteModelHeader(int num)
        {
            /*
             * data.header.blockSize = br.ReadUInt32();
                data.header.bonesOffset = br.ReadUInt32();
                data.header.materialOffset = br.ReadUInt32();
                data.header.polygonStartOffset = br.ReadUInt32();
                data.header.polygonEndOffset = br.ReadUInt32();
                data.header.unknown1 = br.ReadByte();
                data.header.unknown2 = br.ReadByte();
                data.header.unknown3 = br.ReadByte();
                data.header.numObjects = br.ReadByte();
                data.header.numMaterial = br.ReadByte();
                data.header.numPolygon = br.ReadByte();
                data.header.unknown4 = br.ReadByte();
                data.header.scaleMode = br.ReadByte();
                data.header.unknown5 = br.ReadUInt64();
                data.header.numVertices = br.ReadUInt16();
                data.header.numSurfaces = br.ReadUInt16();
                data.header.numTriangles = br.ReadUInt16();
                data.header.numQuads = br.ReadUInt16();
                data.header.boundingX = Get_SignedFixedPoint(br.ReadUInt16());
                data.header.boundingY = Get_SignedFixedPoint(br.ReadUInt16());
                data.header.boundingZ = Get_SignedFixedPoint(br.ReadUInt16());
                data.header.boundingWidth = Get_SignedFixedPoint(br.ReadUInt16());
                data.header.boundingHeight = Get_SignedFixedPoint(br.ReadUInt16());
                data.header.boundingDepth = Get_SignedFixedPoint(br.ReadUInt16());
                data.header.unused = br.ReadUInt64();
             */

            writer.Write(model.model.mdlData[num].header.blockSize);
            writer.Write(model.model.mdlData[num].header.bonesOffset);
            writer.Write(model.model.mdlData[num].header.materialOffset);
            writer.Write(model.model.mdlData[num].header.polygonStartOffset);
            writer.Write(model.model.mdlData[num].header.polygonEndOffset);
            writer.Write(model.model.mdlData[num].header.unknown1);
            writer.Write(model.model.mdlData[num].header.unknown2);
            writer.Write(model.model.mdlData[num].header.unknown3);
            writer.Write(model.model.mdlData[num].header.numObjects);
            writer.Write(model.model.mdlData[num].header.numMaterial);
            writer.Write(model.model.mdlData[num].header.numPolygon);
            writer.Write(model.model.mdlData[num].header.unknown4);
            writer.Write(model.model.mdlData[num].header.scaleMode);
            writer.Write(model.model.mdlData[num].header.unknown5);
            writer.Write(model.model.mdlData[num].header.numVertices);
            writer.Write(model.model.mdlData[num].header.numSurfaces);
            writer.Write(model.model.mdlData[num].header.numTriangles);
            writer.Write(model.model.mdlData[num].header.numQuads);
            //byte[] buffer = BitConverter.GetBytes(model.model.mdlData[num].header.boundingX);
            writer.Write(BitConverter.GetBytes(model.model.mdlData[num].header.boundingX));
            writer.Write(BitConverter.GetBytes(model.model.mdlData[num].header.boundingY));
            writer.Write(BitConverter.GetBytes(model.model.mdlData[num].header.boundingZ));
            writer.Write(BitConverter.GetBytes(model.model.mdlData[num].header.boundingWidth));
            writer.Write(BitConverter.GetBytes(model.model.mdlData[num].header.boundingHeight));
            writer.Write(BitConverter.GetBytes(model.model.mdlData[num].header.boundingDepth));
            writer.Write(model.model.mdlData[num].header.unused);
        }
    }
}
